/*--------------------------------------------------------------------------------------*\
**
** Heroes IV
** Copyright 2000, The 3DO Company
**
** adv_object_list_image.cpp
**
\*--------------------------------------------------------------------------------------*/
// kill the 255+ character identifier warning.  Templates tend to exceed that easily.
#include "precompiled.h"
#pragma warning( disable: 4786 )
#include "adv_object_list_image.h"

#include "adaptor_handler.h"
#include "adv_dwelling.h"
#include "adventure_map.h"
#include "adventure_object.h"
#include "bitmap_group.h"
#include "bitmap_group_cache.h"
#include "bitmap_layer_window.h"
#include "bound_handler.h"
#include "buffer_window.h"
#include "building_traits.h"
#include "button.h"
#include "creature_traits.h"
#include "elements_of.h"
#include "enum_operations.h"
#include "external_string.h"
#include "footprint.h"
#include "map_rect.h"
#include "memory_bitmap.h"
#include "micro_map_window.h"
#include "replace_keywords.h"
#include "scrollbar.h"
#include "terrain.h"
#include "town.h"
#include "town_drawing.h"
#include "town_list.h"
#include "town_properties.h"

namespace
{
	t_bitmap_group_cache const k_bar_graphs( "town.graph" );
};

// --------------------------------------------------
// object to create a thumbnail image of the town
// or other adventure object
// --------------------------------------------------
t_adv_object_list_image::t_adv_object_list_image( t_mode mode )
{
	m_bar_graphs = k_bar_graphs.get();
	m_mode = mode;
}

// --------------------------------------------------
// object to create a thumbnail image of the town
// or other adventure object
// --------------------------------------------------
void t_adv_object_list_image::create_renderer( t_adventure_map const& map,
											   int team_view,
											   t_screen_point const& view_size,
											   t_bitmap_layer_ptr object_marker )
{
	t_level_map_point_2d const& object_pos = m_object->get_position();
	t_map_point_2d const& object_size = m_object->get_footprint().get_size();

	m_map_renderer =
		new t_micro_map_renderer( map, object_pos.level, team_view, view_size, object_marker, t_map_rect_2d( object_pos, object_size ) );
}

// --------------------------------------------------
// object to create a thumbnail image of the town
// or other adventure object
// --------------------------------------------------
t_micro_map_renderer& t_adv_object_list_image::get_map_renderer( t_adventure_map const& map,
																 int team_view,
																 t_screen_point const& view_size,
																 t_bitmap_layer_ptr object_marker )
{
	if (m_map_renderer.get() == 0)
		create_renderer( map, team_view, view_size, object_marker );
	return *m_map_renderer;
}

// --------------------------------------------------
// object to create a thumbnail image of the town
// or other adventure object
// For towns ONLY: draw a bar graph based on the # of buildings of a type in the town.
// --------------------------------------------------
void t_adv_object_list_image::draw_bar( std::string dest_layer_name,
										std::string source_layer_name,
										t_town * town,
										t_town_building const* buildings, int count, int limit )

{
	t_screen_rect		  dest_rect     = m_thumbnails->find( dest_layer_name )->get_rect();
	t_screen_rect		  source_rect   = dest_rect;
	t_bitmap_layer const* layer			= m_bar_graphs->find( source_layer_name );
	t_bitmap_layer const* shadow		= m_bar_graphs->find( source_layer_name + " shadow" );
	int                   value = 0;
	int					  maximum = 0;
	t_town_building       building;
	int                   i;

	for (i = 0; i < count; i++)
	{
		building = buildings[i];
		if (town->is_legal( building ))
		{
			maximum++;
			if (town->has( building ))
				value++;
		}
	}
	if (maximum > limit)
		maximum = limit;
	source_rect -= dest_rect.top_left(); // normalize rectangle
	// change width
	if (maximum == 0)
		source_rect.right = 0;
	else
		source_rect.right = (source_rect.right - 1) * value / maximum;
	source_rect.bottom--;
	source_rect += t_screen_point(1,1);
	shadow->draw_to( source_rect, *m_image.get_bitmap(), 
		             dest_rect.top_left() + t_screen_point(1,1));
	source_rect -= t_screen_point(1,1);
	layer->draw_to( source_rect, *m_image.get_bitmap(), dest_rect.top_left() );
}

static const t_town_building k_creature_dwellings[] =
{
	k_town_dwelling_1,
	k_town_dwelling_2,
	k_town_dwelling_3,
	k_town_dwelling_4,
	k_town_dwelling_5,
	k_town_dwelling_6,
	k_town_dwelling_7,
	k_town_dwelling_8,
	k_town_portal,
};

static const t_town_building k_magic_buildings[] =
{
	k_town_mage_guild_1,
	k_town_mage_guild_2,
	k_town_mage_guild_3,
	k_town_mage_guild_4,
	k_town_mage_guild_5,
	k_town_library_1,
	k_town_library_2,
};

static const t_town_building k_misc_buildings[] =
{
	k_town_village_hall,
	k_town_hall,
	k_town_city_hall,
	k_town_caravan,
	k_town_prison,
	k_town_tavern,
	k_town_blacksmith,

	// life-specific
	k_town_seminary,
	k_town_stables,
	k_town_abbey,

	// order-specific
	k_town_university,
	k_town_treasury,

	// death-specific
	k_town_skeleton_transformer,
	k_town_necromancy_amplifier,

	// chaos-specific
	k_town_academy,
	k_town_training_grounds, // also appears in might town
	k_town_mana_vortex,

	// nature-specific
	k_town_portal,
	k_town_rainbow,
	k_town_grove,

	// might-specific
	k_town_breeding_pit,
	k_town_magic_dampener,
	k_town_arena,
};

// --------------------------------------------------
// object to create a thumbnail image of the town
// or other adventure object
// --------------------------------------------------
t_image_buffer const& t_adv_object_list_image::get_bitmap() 
{
	if (m_image.get_bitmap() == 0)
	{
		t_bitmap_layer const*		background = m_thumbnails->find( k_terrain_keyword[m_terrain] );
		t_bitmap_layer const*       layer;

		m_image = t_image_buffer( background->get_width(), background->get_height() );

		t_abstract_bitmap16*		buffer = m_image.get_bitmap();

		background->draw_to( *buffer );

		layer = m_thumbnails->find( m_building_keyword );
		if (layer != 0)
			layer->draw_to( *buffer );

		// Extras for towns
		t_town * town = dynamic_cast< t_town * >( m_object.get() );

		if ( town != NULL )
		{
			m_drawn_buildings = town->get_buildings();
			draw_bar( "misc", "misc", town, k_misc_buildings, ELEMENTS_OF( k_misc_buildings ), 100 );
			draw_bar( "magic", "magic", town, k_magic_buildings, ELEMENTS_OF( k_magic_buildings ), 100 );
			draw_bar( "creatures", "creatures", town, k_creature_dwellings, 
					  ELEMENTS_OF( k_creature_dwellings ), 6 );
		}
	}
	return m_image;
}

// --------------------------------------------------
// object to create a thumbnail image of the town
// or other adventure object
// --------------------------------------------------
void t_adv_object_list_image::set_dwelling( t_adv_dwelling* dwelling )
{
	if (m_object.get() != dwelling)
	{
		m_image = t_image_buffer();
		m_map_renderer = 0;
		m_object = dwelling;
		m_building_keyword = get_keyword( dwelling->get_creature_type() );
		t_town_type type = get_traits( dwelling->get_creature_type() ).alignment;
		m_thumbnails = get_town_thumbnail( type, m_mode == k_mode_tiny ? 89 : 140 );

		t_adv_map_point point;
		if ( dwelling->get_trigger_cell( point ) )
		{
			t_adventure_map & map = *dwelling->get_map();
			m_terrain = map[ point ].get_terrain();
		}
		else
		{
			m_terrain = k_terrain_grass;
		}

		m_terrain = get_basic_terrain( m_terrain );
	}
}



// --------------------------------------------------
// object to create a thumbnail image of the town
// or other adventure object
// --------------------------------------------------
void t_adv_object_list_image::set_town( t_town* town )
{
	if (m_object.get() != town || m_drawn_buildings != town->get_buildings())
	{
		m_image = t_image_buffer(); 
		if (town->has( k_town_castle ))
			m_building_keyword = "castle";
		else if (town->has( k_town_citadel ))
			m_building_keyword = "citadel";
		else if (town->has( k_town_fort ))
			m_building_keyword = "fort";
		else
			m_building_keyword = "village";
	}

	if (m_object.get() != town)
	{
		m_map_renderer = 0;
		m_object = town;
		m_thumbnails = get_town_thumbnail( town->get_type(), m_mode == k_mode_tiny ? 89 : 140 );
		m_terrain = get_basic_terrain( town->get_terrain() );
	}
}
